﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Linq;
using System.Text;
using System.Reflection;
using BMC.ARSystem;


namespace Wicresoft.EKA.NRemedy.Linq
{
    public class ARQueryProvider<T> : QueryProvider where T:ARBaseForm
    {
        protected object context;

        public ARQueryProvider(object context)
        {
            this.context = context;
        }

        public override object Execute(Expression expression)
        {
            //translate expression
            //visit Evalable expression
            expression = Evaluator.PartialEval(expression);
            //translate
            TranslateResult tr = this.Translate(expression);
            if (tr.Count)
            {
                ARProxy4Linq<T> proxy = (ARProxy4Linq<T>)Activator.CreateInstance(
                   typeof(ARProxy4Linq<T>), context);
                return proxy.GetEntryCountByQuery(tr.Qulification.ToString());
            }

            //special "Select" clause apply
            else if (tr.Select)
            {
                tr.TargetType = TypeSystem.GetElementType(expression.Type);
                ARProxy4Linq<T> proxy = (ARProxy4Linq<T>)Activator.CreateInstance
                    (typeof(ARProxy4Linq<T>), context);

                return proxy.GetEntryByQuery(
                    tr.Qulification.ToString(),
                    tr.SelectedProperties,
                    tr.TargetType,
                    tr.SelectExpression
                    );
            }
            else
            {
                ARProxy4Linq<T> proxy = (ARProxy4Linq<T>)Activator.CreateInstance(
                    typeof(ARProxy4Linq<T>), context);
                return proxy.GetListEntry(tr.Qulification.ToString());
            }
        }

        public override string GetQueryText(Expression expression)
        {
            return this.Translate(expression).ToString();
        }

        private TranslateResult Translate(Expression expression)
        {
            return new QueryVisitor().Translate(expression);
        }
    }


    public class SubtreeEvaluator : System.Linq.Expressions.ExpressionVisitor
    {

        public Expression Eval(Expression exp)
        {
            return this.Visit(exp);
        }

        public override Expression Visit(Expression exp)
        {
            if (exp == null)
            {
                return null;
            }
            if (exp.NodeType != ExpressionType.Parameter)
            {
                return this.Evaluate(exp);
            }
            return base.Visit(exp);
        }

        private Expression Evaluate(Expression e)
        {
            if (e.NodeType == ExpressionType.Constant)
            {
                return e;
            }
            LambdaExpression lambda = Expression.Lambda(e);
            Delegate fn = lambda.Compile();
            return Expression.Constant(fn.DynamicInvoke(null), e.Type);
        }
    }
}
